#include<stdio.h>
#include<dos.h>
#include"memrw.h"
#include"usb.h"
#include"storage.h"
#include"hid.h"
#include"ohci.h"
#include"uhci.h"


LIST_ENTRY  USBControllerList;
LIST_ENTRY  USBDeviceList;
main()
{

          initUSB();
#ifdef DEBUG
//	   showAddDeviceInfo();
//          testHID();
		testHID();
//     	   testStorage();
//showAllController();
showAllDevice();
//getHIDdevice();
#endif

	   	
}


void initUSB()
{
	 coreSetLimits(8,8);
         //2  clear global data
	  InitializeList(&USBControllerList);
	  InitializeList(&USBDeviceList);


       BYTE bus =0 , dev =0 ,func =0 ;
       for(bus=0;bus<0x10;bus++)
       {
                 for(dev=0;dev<=0x1f;dev++)
                 {
                         for(func=0;func<0x08;func++)
                         {                   
					     if(Read_PCI_Word(bus,dev,func ,0x0a)==0x0c03)
					     	{
					     		initController(bus,dev,func);							          		  
					     	}
					     else
					     	{
					     	    if(func ==0) //multi function
					     	    {
					     	        if((Read_PCI_Byte(bus,dev,func ,0x0e) & 0x80) ==0x80);
							 else break;
					     	    }						    	
					     	}		

				}
                 }
       }

	return;   
}



/******************************************************************************
    Function:
        initController

    Description:
	allocate memory for a controller as  HCStrucType type.
	insert this controller into USBControllerList.
	init lDeviceList in HCStrucType type.

    Entry:
	bus,dev,func ---PCI address

    Exit:
        HCStrucType pointer.
******************************************************************************/
void initController(BYTE bus,BYTE dev,BYTE func)
{
	HCStrucType * pHC;
	
	//alocate memory
	BYTE * pMem=allocAlignMem(sizeof(HCStrucType),1);
	pHC= (HCStrucType *)pMem;
	
	//insert controller loop
	InsertTailList(&USBControllerList, &pHC->lControllerList);
	
	//init device loop
	InitializeList(&pHC->lDeviceList);

	 WORD temp1=bus;
	  temp1 <<=5;
	  temp1 +=dev;
	  temp1 <<=3;
	  temp1 +=func;
	  pHC->wBusDevFuncNum=temp1;

	 if(Read_PCI_Byte(bus,dev,func ,0x09)==0x00)	//UHCI	//ICH7 platform		
	{
	      	#ifdef DEBUG
   	      	        printf("UHCI Controller init start.... dev:%d,  func: %d\n",dev,func);
     	      	 #endif       
		      
	        //stop USB SMI 										          
              BYTE  pciValue=Read_PCI_Byte(bus,dev,0,0xc0);
	       pciValue &= 0xe0; //clear  bit4 =  usb smi enable	
	       Write_PCI_Byte(bus,dev,0,0xc0,pciValue);    															 
								  
	       pHC->dBaseAddress=Read_PCI_DWord( bus,  dev,  func, 0x20) & 0xffffffe0;
	       pHC->pHCDPointer=getUHCIMethod();	       



		 pHC->pHCDPointer->controllerInitial(pHC); //place here temp, for have no OHC,EHCI support
	 }
	 
 	if(Read_PCI_Byte(bus,dev,func ,0x09)==0x10)	//OHCI	//AMD SB710 PLATFORM
	{
	      	#ifdef DEBUG
   	      	        printf("OHCI Controller init start.... dev:%d,  func: %d\n",dev,func);
     	      	 #endif       
	       pHC->dBaseAddress=Read_PCI_DWord( bus,  dev,  func, 0x10) & 0xffffffe0;	
		//ownership handoff
		setMemDWORD(pHC->dBaseAddress + HcCommandStatus,-1,8);//OwnershipChangeRequest
		while(getMemDWORD(pHC->dBaseAddress  + HcControl) & 0x100){} //check InterruptRouting 1-SMI;0-interrup.

				
	       pHC->pHCDPointer=getOHCIMethod();	
		pHC->pHCDPointer->controllerInitial(pHC); //place here temp, for  no EHCI support				 
	}
	if(Read_PCI_Byte(bus,dev,func ,0x09)==0x20)	//EHCI			
	{
	}	  
	 
//		 pHC->pHCDPointer->controllerInitial(pHC);

}



/******************************************************************************
    Function:
      getUSBDeviceList

    Description:
  	get USBDeviceList.

    Entry:
	none

    Exit:
	return USBDeviceList
******************************************************************************/
LIST_ENTRY *getUSBDeviceList()
{
	return &USBDeviceList;
}


/******************************************************************************
    Function:
      devInitialize

    Description:
  	init  device on specified port , and save information in device description.

    Entry:
	pHC  -- host controller description
	portIndex  -- port index under host controller	

    Exit:
	none
******************************************************************************/
void devInitialize(HCStrucType * pHC,BYTE portIndex)
{	

	  BYTE status=0;
	   //init device description
	   DeviceInfoPtr DIPtr=(DeviceInfoPtr)allocAlignMemInBox(sizeof(DeviceInfoType), 1);
 	   InsertTailList(getUSBDeviceList(), &DIPtr->lDeviceList);

	   InsertTailList(&pHC->lDeviceList, &DIPtr->lDeviceUnderControllerList);
	   HCStrucType * HCPtr=pHC;
          DIPtr->pHCStrucPtr= HCPtr;
  
	   BYTE (* pmCT)(DeviceInfoPtr, RequstFormatType *) = HCPtr ->pHCDPointer->ControlTransfer;
		  
          //2. set default value to init
          DIPtr->bHubPortNumber=portIndex;
          DIPtr->bDeviceAddress=0;
          DIPtr->bDataSync=0;
	   HCPtr->pHCDPointer->DevPortInit(DIPtr,portIndex);
	   if(DIPtr->bEndpointSpeed == Low_Speed_Device)DIPtr->wEndp0MaxPacket=8;
	   else if(DIPtr->bEndpointSpeed == High_Speed_Device)DIPtr->wEndp0MaxPacket=64;
	   else DIPtr->wEndp0MaxPacket=8;//this value need to read first 8 byte of device descriptor.
	   
           //2. get device descriptor
           RequstFormatType AddressRequest={0x80,GET_DESCRIPTOR,0x100,0,0x12};        
	   status=(*pmCT)(DIPtr, &AddressRequest);
	   BYTE * ConTransBufferPtr;  	  
	   ConTransBufferPtr=HCPtr ->pHCDPointer->pointToDevBuffer(DIPtr);
	   
           deviceDescriptorType *dDTPtr= (deviceDescriptorType *)ConTransBufferPtr;

           DIPtr->bDeviceType=dDTPtr->bDeviceClass;
	    DIPtr->bSubClassCode=dDTPtr->bDeviceSubClass;
	    DIPtr->bProtocolCode=dDTPtr->bDeviceProtocol;
	    DIPtr->wEndp0MaxPacket=dDTPtr->bMaxPacketSize;
		
	    //need get again, for last time we may only get 8 bytes accord spec usb 2.0 section 5.5.3.
	    if(status)(*pmCT)(DIPtr, &AddressRequest); 
	   
          DIPtr->wVendorId= dDTPtr->widVendor;
	   DIPtr->wDeviceId= dDTPtr->widProduct;
	   DIPtr->bNumConfigs=dDTPtr->bNumConfigurations;

          if(dDTPtr->biManufacture || dDTPtr->biProduct || dDTPtr->biSerialNumber)
          {
          	 BYTE ManufacturerSIndex=  dDTPtr->biManufacture; 
		 BYTE ProductSIndex=  dDTPtr->biProduct;
		 BYTE SerialNumberIndex= dDTPtr->biSerialNumber;
		 WORD LanguageID;
		 
               //2. get language ID
              RequstFormatType AddressRequest3={0x80,GET_DESCRIPTOR,(STRING<<8) ,0,0xff};     
	
	 	 (*pmCT)(DIPtr, &AddressRequest3);
              LanguageID = (ConTransBufferPtr[3] <<8 )+ ConTransBufferPtr[2] ;	
			  
               //2. get manufacturer string
               if(ManufacturerSIndex)
               {
                    AddressRequest3.wValue= (STRING<<8) + ManufacturerSIndex;
		      AddressRequest3.wIndex= LanguageID;
	 	      (*pmCT)(DIPtr, &AddressRequest3);
		      storeStringDescriptor(ConTransBufferPtr, DIPtr->sManufacture);			      		
               }
               //2. get product string
               if(ProductSIndex)
               {
                    AddressRequest3.wValue= (STRING<<8) + ProductSIndex;
		      AddressRequest3.wIndex= LanguageID;                  
	
	             (*pmCT)(DIPtr, &AddressRequest3);
		      storeStringDescriptor(ConTransBufferPtr, DIPtr ->sProduct);			
		      		
               }

               //2. get serial number string
               if(SerialNumberIndex)
               {
                    AddressRequest3.wValue= (STRING<<8) + SerialNumberIndex;
		      AddressRequest3.wIndex= LanguageID;                   
	
 	             (*pmCT)(DIPtr, &AddressRequest3);
		      storeStringDescriptor(ConTransBufferPtr, DIPtr ->sSerialNumber);			
		      		
               }			   
			   
          }		   

          //2.set device address
          //get USB address from controller.
           RequstFormatType AddressRequest1={0,SET_ADDRESS,0,0,0};        	 
           BYTE USBAddress= ++ HCPtr->bMaxAddress ;
           AddressRequest1.wValue=USBAddress  ;
 	   (*pmCT)(DIPtr, &AddressRequest1);
           DIPtr->bDeviceAddress =USBAddress ;  

	   delay(2);//spec required.	   
		   
          //2. get device config
          //new address!!
          // just get the first configuration. need.....
           RequstFormatType AddressRequest2={0x80,GET_DESCRIPTOR,CONFIGURATION<<8,0,0xff};        	 // 

 	   (*pmCT)(DIPtr, &AddressRequest2);
           parseConfigurationString(ConTransBufferPtr,  DIPtr);
      
          //2. set device config
            RequstFormatType AddressRequest4={0x00,SET_CONFIGURATION,0,0,0};          
            AddressRequest4.wValue=DIPtr->bConfigNum;   
	   (*pmCT)(DIPtr, &AddressRequest4);

	   //2. init specific dev
/*
	   DevDriverMethodType * pDev=0;
	   switch(DIPtr->bDeviceType)
	   {
	   	case MassStorageClass: 
			pDev= getMassDevMethod();
			pDev->DevInit(DIPtr);
			break;
		default:	break;
	   }
	   */

	    return;  
	  	  
}


void parseConfigurationString(BYTE * stringPtr,  DeviceInfoPtr devicePtr)
{
            //2. configuration descriptor
             configurationDescriptorType * CDPtr=(configurationDescriptorType *)stringPtr;
             //WORD  TotalLength=CDPtr->wTotalLength;
			 
             devicePtr->bInterfaceNum = CDPtr->bNumInterfaces;
	     devicePtr->bConfigNum=CDPtr->bConfigurationValue;
             //2. interface descriptor

		// just deal with only one interface.  need all???
		// 
		
	     interfaceDescriptorType * IDPtr=(interfaceDescriptorType *) (stringPtr	+ sizeof(configurationDescriptorType) );
	     devicePtr->bAltSettingNum = IDPtr->bAlternateSetting;

            if(devicePtr->bDeviceType == 0)
            	{
	              devicePtr->bDeviceType = IDPtr->bInterfaceClass;  
	              devicePtr->bSubClassCode = IDPtr ->bInterfaceSubClass;
	              devicePtr->bProtocolCode = IDPtr ->bInterfaceProtocol;
            	}
	     BYTE EndPointNum=IDPtr->bNumEndpoints;

	      devicePtr->bEndpointNum=EndPointNum +1 ; // add number of default endpoint. assume 1 interface .

          
            //2. endpoint descriptor
	   endpointDescriptorType * EPDPtr;

          for(int i=0; i<EndPointNum; i++)
          {

	    EPDPtr=(endpointDescriptorType *)(stringPtr + sizeof(configurationDescriptorType)  + \
			sizeof(interfaceDescriptorType) + sizeof(endpointDescriptorType) * i);

          // HID device , refer to HID spec Appendix E.4
          if(devicePtr->bDeviceType == HIDClass)
	    EPDPtr=(endpointDescriptorType *)(stringPtr + sizeof(configurationDescriptorType)  + \
			sizeof(interfaceDescriptorType) + sizeof(endpointDescriptorType) * i + 9); //HID descriptor length
		  
	     if((EPDPtr->bmAttributes & 0x3)==2) //bulk endpoint
	     {
	              if(EPDPtr->bEndpointAddress  & 0x80)  // IN endpoint
	              {
	                     devicePtr->bBulkInEndpoint=EPDPtr->bEndpointAddress & 0x0f;
			     devicePtr->wBulkInMaxPkt= EPDPtr->wMaxPacketSize;
	              }
	              else			                                   // OUT endpoint
	              {
	                     devicePtr->bBulkOutEndpoint=EPDPtr->bEndpointAddress & 0x0f;
			     devicePtr->wBulkOutMaxPkt= EPDPtr->wMaxPacketSize;	              
	              }
	     }

	     if((EPDPtr->bmAttributes & 0x3)==3) //interrupt endpoint
	     {
	              if(EPDPtr->bEndpointAddress  & 0x80)  // IN endpoint
	              {
	                     devicePtr->bIntEndpoint=EPDPtr->bEndpointAddress & 0x0f;
			       devicePtr->wIntMaxPkt= EPDPtr->wMaxPacketSize;
				devicePtr->bInterval = EPDPtr->bInterval;
	              }	
	     }			 
	}	 
			 
	return;		 
}

//note: just support 31 characters. refer to device define area.
void storeStringDescriptor(BYTE * SourceStr, BYTE * DestStr)
{
          BYTE i=0;
	   BYTE length=SourceStr[0];
	   for(int j =2; (j<length) && (i < 32); j=j+2)
	   {
	           DestStr[i ++]=SourceStr[j];
	   }
	   DestStr[i]=0;
	   return;
}


#ifdef DEBUG
/*
void testHID()
{
//      setCurrentDeviceInfoIndex(0);
//      setCurrentDeviceInfoIndex(getNextDeviceIndex(3,0xff, 0xff));
      printf("CurrentDeviceInfoIndex:  %d \n",CurrentDeviceInfoIndex);	 




  //    DeviceInfoPtr DIP= getDeviceData(getCurrentDeviceIndex());
      HCStrucType * pHC=DIP->pHCStrucPtr;

      RequstFormatType AddressRequest2={0x80,GET_DESCRIPTOR,CONFIGURATION<<8,0,0xff};        	  

      
      pHC->pHCDPointer->ControlTransfer(DIP,&AddressRequest2);

      dump(pHC->pDescriptorPtr->UDescriptor.buffer1, 256);



      printf("get REPORT DESCRIPTOR \n");
      RequstFormatType AddressRequest3={0x81,GET_DESCRIPTOR,0x22<<8,0,0xff};     	  
      pHC->pHCDPointer->ControlTransfer(DIP,&AddressRequest3);

      dump(pHC->pDescriptorPtr->UDescriptor.buffer1, 256);


	  
}

*/
void testStorage()
{  

	LIST_ENTRY * pLE;
	DeviceInfoType * pDI=0;
	BYTE flag=0;
	for(pLE = USBDeviceList.ForwardLink;  pLE != &USBDeviceList; pLE= pLE->ForwardLink)
	{
		pDI =DEVICE_FROM_LIST_ENTRY(pLE);
		if(pDI->bDeviceType == MassStorageClass)
		{
			flag=1;
			break;
		}
	}
	printf("read storage \n");
	
       BYTE data[512*4];
	cleanBuffer(data, 512*4);
	if(flag)	   
	{
		MassINQUIRY(data,pDI);
		dump(data, 512*1);

		MassREAD10(1, 1, data, pDI);
		dump(data, 512*1);
	}


       return;	  
}

void testHID()
{  

	LIST_ENTRY * pLE;
	DeviceInfoType * pDI=0;
	BYTE flag=0;
	for(pLE = USBDeviceList.ForwardLink;  pLE != &USBDeviceList; pLE= pLE->ForwardLink)
	{
		pDI =DEVICE_FROM_LIST_ENTRY(pLE);
		if(pDI->bDeviceType == HIDClass)
		{
			flag=1;
			break;
		}
	}
	printf("test HID\n");
	
       BYTE data[512];
	WORD length=0;  	
	cleanBuffer(data, 512);
	
	if(flag)	   
	{
	
	   BYTE (*pInt)(DeviceInfoPtr , BYTE , BYTE * ,WORD ,WORD * )= \
	   	pDI->pHCStrucPtr->pHCDPointer->interruptTransfer;

	   for(int i =0;i <100;i++)
	   {
	   	printf("please input key....\n");
		delay(20);
		(*pInt)(pDI,0x80,data,8,&length);
		dump(data, 16);
		printf("\n");

	   }
	}


       return;	  
}


void showDeviceInfo(DeviceInfoPtr devicePtr)
{

	  printf("device information start----------------\n");
	  printf("%s,  %s,  %s\n",devicePtr->sManufacture,devicePtr->sProduct,devicePtr->sSerialNumber);
         printf("bDeviceType : %x \n",devicePtr->bDeviceType);
         printf("bSubClassCode : %x \n",devicePtr->bSubClassCode);		 
         printf("bProtocolCode : %x \n",devicePtr->bProtocolCode);			
         printf("wVendorId : %x \n",devicePtr->wVendorId);
         printf("wDeviceId : %x \n",devicePtr->wDeviceId);		 	  	
         printf("bHubDeviceNumber : %x \n",devicePtr->bHubDeviceNumber);		  
         printf("bHubPortNumber : %x \n",devicePtr->bHubPortNumber);				 
         printf("bDeviceAddress : %x \n",devicePtr->bDeviceAddress);
         printf("bEndpointNum : %x \n",devicePtr->bEndpointNum);		 
         printf("bEndpointSpeed : %x \n",devicePtr->bEndpointSpeed);			
         printf("wEndp0MaxPacket : %x \n",devicePtr->wEndp0MaxPacket);
	  printf("\n");	 
		 
         printf("bBulkInEndpoint : %x  wBulkInMaxPkt : %x \n",devicePtr->bBulkInEndpoint,devicePtr->wBulkInMaxPkt);		 
         printf("bBulkOutEndpoint : %x  wBulkOutMaxPkt : %x \n",devicePtr->bBulkOutEndpoint,devicePtr->wBulkOutMaxPkt);		 
         printf("bIntEndpoint : %x  wIntMaxPkt : %x  \n",devicePtr->bIntEndpoint,devicePtr->wIntMaxPkt);	 
	  printf("\n");	 
		 
         printf("bNumConfigs : %x \n",devicePtr->bNumConfigs);	
         printf("bConfigNum : %x \n",devicePtr->bConfigNum);		 
         printf("bInterfaceNum : %x \n",devicePtr->bInterfaceNum);		
         printf("bAltSettingNum : %x \n",devicePtr->bAltSettingNum);		  	 
	 
         return;		 
}

void showAllDevice()
{
	LIST_ENTRY * pLE;
	DeviceInfoType * pDI;
	for(pLE = USBDeviceList.ForwardLink;  pLE != &USBDeviceList; pLE= pLE->ForwardLink)
	{
		pDI =DEVICE_FROM_LIST_ENTRY(pLE);
		showDeviceInfo(pDI);	
	}
}



void showController(HCStrucType * HCPtr)
{      
        printf("..........controller start.............\n");

        printf("bHCType: %x \n",HCPtr->bHCType);		
        printf("dHcdDataArea: %lx \n",HCPtr->dHcdDataArea);
        printf("dBaseAddress: %lx \n",HCPtr->dBaseAddress);		
        printf("bNumPorts: %x \n",HCPtr->bNumPorts);
        printf("wBusDevFuncNum: %x \n",HCPtr->wBusDevFuncNum);
        printf("pIRQInfoPtr: %lx \n",HCPtr->pIRQInfoPtr);		

        printf("pDescriptorPtr: %04x \n",HCPtr->pDescriptorPtr);		
        printf("pHCDPointer: %04x \n",HCPtr->pHCDPointer);
        printf("wAsyncListSize: %x \n",HCPtr->wAsyncListSize);	
			
}

void showAllController()
{
	LIST_ENTRY  *pLE;
	HCStrucType * pHC;
	for(pLE = USBControllerList.ForwardLink; pLE != &USBControllerList; pLE=pLE ->ForwardLink)
	{
		pHC= CONTROLLER_FROM_LIST_ENTRY(pLE);
		showController(pHC);
	}
}


void getHIDdevice()
{	
	LIST_ENTRY * pLE;
	DeviceInfoType * pDI;
	for(pLE = USBDeviceList.ForwardLink;  pLE != &USBDeviceList; pLE= pLE->ForwardLink)
	{
		pDI =DEVICE_FROM_LIST_ENTRY(pLE);
		//showDeviceInfo(pDI);	
		if(pDI->bDeviceType == HIDClass)
		{
			BYTE (* pmIT)(DeviceInfoPtr , BYTE , BYTE * ,WORD ,WORD * ) = pDI->pHCStrucPtr->pHCDPointer->interruptTransfer;
			WORD Length=0;
			BYTE Buffer[9];
			for(int i=0;i <9; i++)
			{
				(* pmIT)(pDI,0x80,Buffer,8,&Length);
				printf("time %d \n",i);
				dump(Buffer, 8);
				delay(500);
			}
			
			break;
		}
	}

}


#endif
